package com.frank.loadinglibrary.special.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/6/3
 * @description
 **/
public class BallJumpElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {

    private final int valueThree = 3;
    private Color[] color;
    private Paint mPaint;
    private Paint mTextPaint;
    private float radius;
    private Shape mShape = Shape.TRIANGLE;
    private Path mPath;
    private Path mTextPath;
    private float moveY = 0;
    private float rotateAngle = 0;

    private Color textColor;
    private int paintTextSize;
    //BASELINE的高度
    private int paintTextBaseline;
    //画出来的文字
    private String mResText;
    //文字的宽度
    private int mTextWidth;
    //默认的画弧形的时候的间距,值越大速度越快，不能超过最大值
    private final int DEFAULT_RECF_SPACE = 6;
    //最大的画弧形的时候的间距
    private final int MAX_RECF_SPACE = 12;
    //最大的画弧形的时候的间距
    private final int MIN_RECF_SPACE = -12;
    //矩形RECF间距
    private int mRecfSpace = 0;
    //向下弯曲的状态
    private final int STATUS_DOWN_CURVE = 0;
    //向上恢复的状态
    private final int STATUS_UP_CURVE = 1;
    //平的状态
    private final int STATUS_FLAT_CURVE = 2;
    private int mCurveStatus = STATUS_FLAT_CURVE;
    //来回弹动的时间
    private final int MAX_SPRING_COUNT = 10;
    private int mSringCount = MAX_SPRING_COUNT;
    private int animatorTime;

    private BallJumpElement(IComponentCallback iComponentCallback) {
        this.callback = iComponentCallback;
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> list = new ArrayList<>();
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(animatorTime);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "moveY = " + moveY + " Angle = " + rotateAngle);
            moveY = (v > 0.5 ? 1 - v : v) * 3 * radius;
            rotateAngle = 360 * v;
            callback.reflushComponent();
        });
        animatorValue.setLoopedListener(animator -> changeShapeAndBendingText());
        list.add(animatorValue);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public BaseAnimationController.IAnimationController<AnimatorValue> initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        super.initPaint();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_STYLE);

        mPath = new Path();
        mTextPath = new Path();

        mTextPaint = new Paint();
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(paintTextSize);
        mTextPaint.setStyle(Paint.Style.FILL_STYLE);
        mTextPaint.setTextAlign(TextAlignment.LEFT);
        mTextWidth = (int) mTextPaint.measureText(mResText);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        drawShape(canvas);
        drawLadingText(canvas);
    }

    private void drawShape(Canvas canvas) {
        canvas.save();
        switch (mShape) {
            case TRIANGLE:
                canvas.rotate(rotateAngle, getWidth() * 0.5f, getHeight() * 0.5f - moveY - radius * (float) Math.tan(Math.toRadians(30)));
                mPaint.setColor(color[0]);
                mPath.reset();
                mPath.moveTo(getWidth() * 0.5f, getHeight() * 0.5f - moveY - 2 * radius * (float) Math.sin(Math.toRadians(60)));
                mPath.lineTo(getWidth() * 0.5f - radius, getHeight() * 0.5f - moveY);
                mPath.lineTo(getWidth() * 0.5f + radius, getHeight() * 0.5f - moveY);
                mPath.close();
                canvas.drawPath(mPath, mPaint);
                break;
            case CIRCLE:
                mPaint.setColor(color[1]);
                mPath.reset();
                canvas.drawCircle(getWidth() * 0.5f, getHeight() * 0.5f - moveY, radius, mPaint);
                break;
            case RECT:
                canvas.rotate(rotateAngle, getWidth() * 0.5f, getHeight() * 0.5f - moveY);
                mPaint.setColor(color[2]);
                mPath.reset();
                mPath.moveTo(getWidth() * 0.5f - radius, getHeight() * 0.5f - moveY + radius);
                mPath.lineTo(getWidth() * 0.5f + radius, getHeight() * 0.5f - moveY + radius);
                mPath.lineTo(getWidth() * 0.5f + radius, getHeight() * 0.5f - moveY - radius);
                mPath.lineTo(getWidth() * 0.5f - radius, getHeight() * 0.5f - moveY - radius);
                mPath.close();
                canvas.drawPath(mPath, mPaint);
                break;
            default:
                break;
        }
        canvas.restore();
    }

    private void drawLadingText(Canvas canvas) {
        drawArcPath();
        mRecfSpace = getRecfSpace();
        if (mRecfSpace >= MAX_RECF_SPACE) {
            mCurveStatus = STATUS_UP_CURVE;
        } else if (mRecfSpace <= MIN_RECF_SPACE) {
            mCurveStatus = STATUS_DOWN_CURVE;
        }
        if (mSringCount < MAX_SPRING_COUNT) {
            mSringCount++;
            callback.reflushComponent();
        } else {
            reset(canvas);
        }
        canvas.drawTextOnPath(mTextPaint, mResText, mTextPath, 0, 0);
    }


    private void changeShapeAndBendingText() {
        switch (mShape) {
            case TRIANGLE:
                mShape = Shape.CIRCLE;
                break;
            case CIRCLE:
                mShape = Shape.RECT;
                break;
            case RECT:
                mShape = Shape.TRIANGLE;
                break;
            default:
                break;
        }
        mSringCount = 0;
        mCurveStatus = STATUS_DOWN_CURVE;
    }

    public enum Shape {
        TRIANGLE, RECT, CIRCLE
    }

    private void reset(Canvas canvas) {
        mRecfSpace = 0;
        drawArcPath();
        mCurveStatus = STATUS_FLAT_CURVE;

    }

    /**
     * 当矩形间距这块如果到了最大弯曲值就
     * 每次递减，反之则递增，平行状态不变
     *
     * @return
     */
    private int getRecfSpace() {
        if (mCurveStatus == STATUS_DOWN_CURVE) {
            return mRecfSpace + DEFAULT_RECF_SPACE;
        } else if (mCurveStatus == STATUS_UP_CURVE) {
            return mRecfSpace - DEFAULT_RECF_SPACE;
        } else {
            return 0;
        }
    }


    /**
     * +
     * 画出弧线路径
     */
    private void drawArcPath() {
        mTextPath.reset();
        //设定起始点
        mTextPath.moveTo((getWidth() - mTextWidth) / 2f, getHeight() / 2f + paintTextBaseline + radius);
        mTextPath.cubicTo(getWidth() / 2f - mTextWidth / 3f, getHeight() / 2f + paintTextBaseline + radius + mRecfSpace,
                getWidth() / 2f + mTextWidth / 3f, getHeight() / 2f + paintTextBaseline + radius + mRecfSpace,
                (getWidth() + mTextWidth) / 2f, getHeight() / 2f + paintTextBaseline + radius);
        mTextPath.close();
    }

    public void apply(BallJumpBuilder ballJumpBuilder) {
        if (ballJumpBuilder.shapeColor == null || ballJumpBuilder.shapeColor.length != valueThree) {
            this.color = new Color[]{Color.WHITE, Color.YELLOW, Color.BLUE};
        } else {
            this.color = ballJumpBuilder.shapeColor;
        }

        this.textColor = ballJumpBuilder.textColor;
        this.radius = ballJumpBuilder.radius;
        this.paintTextSize = ballJumpBuilder.paintTextSize;
        paintTextBaseline = paintTextSize;
        this.mResText = ballJumpBuilder.resText;
        this.animatorTime = ballJumpBuilder.animatorTime;
        initPaint();
    }

    public static class BallJumpBuilder {
        private IComponentCallback iComponentCallback;
        private Color[] shapeColor;
        private Color textColor = Color.WHITE;
        private float radius = 40f;
        private int paintTextSize = 30;
        private String resText = "正在加载。。。";
        private int animatorTime = 1000;

        public BallJumpBuilder(IComponentCallback iComponentCallback) {
            this.iComponentCallback = iComponentCallback;
        }

        public BallJumpBuilder setColor(Color[] shapeColor) {
            this.shapeColor = shapeColor;
            return this;
        }

        public BallJumpBuilder setTextColor(Color textColor) {
            this.textColor = textColor;
            return this;
        }

        public BallJumpBuilder setRadius(float radius) {
            this.radius = radius;
            return this;
        }

        public BallJumpBuilder setPaintTextSize(int paintTextSize) {
            this.paintTextSize = paintTextSize;
            return this;
        }

        public BallJumpBuilder setResText(String resText) {
            this.resText = resText;
            return this;
        }

        public BallJumpBuilder setAnimatorTime(int animatorTime) {
            this.animatorTime = animatorTime;
            return this;
        }

        public BallJumpElement build() {
            BallJumpElement ballJumpElement = new BallJumpElement(iComponentCallback);
            ballJumpElement.apply(this);
            return ballJumpElement;
        }
    }
}
